#include "./SimulateAttac6Boom.j"

// 寒冰箭
// 打中单位后可以分裂
library SimulateAttac6 initializer init requires SimulateAttac6Boom

    // 冲击 击退200码
    // 分裂 分裂为3个小寒冰箭
    // 极霜 命中后冻结怪物2秒
    // 小蚀骨 小寒冰箭也能叠加冻伤的效果
    // 蚀骨 命中后施加10秒可叠加5次的冻伤
    // 连发 伤害-20%
    // 贯穿


    // 剑气斩
    // 瓦解 5秒内受到的伤害=25%



    globals
        // 基础伤害 攻击力*0.5

        // 寒冰箭等级（默认0）
        integer array ct_hbjLevel
        // 寒冰箭释放CD（默认3秒）
        real array ct_hbjCD
        // 寒冰箭释放距离(默认2600)
        real array ct_hbjRDis
        // 寒冰箭连射数量（默认0）
        integer array ct_hbjCount
        // 寒冰箭伤害增幅（默认0%）
        real array ct_hbjDmZf
        // 寒冰箭命中是否有冻结（默认false）
        boolean array ct_hbjDongj
        // 寒冰箭命中冻结等级(默认1，每级增加0.5秒)
        integer array ct_hbjDongjLevel
        // 寒冰箭命中是否减速（默认false）
        boolean array ct_hbjIsJS
        // 减速持续4秒
        // 寒冰箭命中减速等级（默认1级，也就是20%减速，每级提升5%，最大80%）
        integer array ct_hbjJSLevel
        // 寒冰箭命中是否冻伤，冻伤持续掉血，每0.3秒掉一次，基础伤害攻击力*0.1（默认false）
        boolean array ct_hbjIsDS
        // 寒冰箭冻伤次数（默认3次）(冻伤的次数和增幅分裂的箭也用这个)
        integer array ct_hbjDSCount
        // 寒冰箭冻伤伤害增幅
        real array ct_hbjDSDmgZf
        // 寒冰箭贯穿个数（默认0，表示不贯穿，打到单位就消失）
        integer array ct_hbjPzCount


        // 寒冰箭命中后是否分裂（默认false）
        boolean array ct_hbjIsBoom
        // 寒冰箭命中单位后分裂数量（默认是3）
        integer array ct_hbjBoomCount
        // 寒冰箭分裂伤害增幅(默认0%)
        real array ct_hbjBoomDmgZf
        // 寒冰箭分裂是否冻结（默认false）
        boolean array ct_hbjBoomDJ
        // 寒冰箭分裂冻结等级（默认1， 每级增加0.5秒）
        integer array ct_hbjBoomDJLevel
        // 寒冰箭分裂命中是否减速（默认false）
        boolean array ct_hbjBoomJS
        // 寒冰箭分裂命中减速等级（默认1级，也就是10%减速，每级提升5%，最大80%
        integer array ct_hbjBoomJSLevel
        // 寒冰箭分裂命中是否冻伤(默认false)
        boolean array ct_hbjBoomIsDS
        // 寒冰箭分裂贯穿个数（默认0，表示不贯穿）
        integer array ct_hbjBoomPZCount


        // 寒冰箭术要冻伤的单位，寒冰箭术每0.3秒一次，冻伤指定次数
        // 父key 玩家id
        // 子key 1表示要玩家要冻伤的怪物Group
        hashtable hbjHash = InitHashtable()

        // 冻结马甲
        unit array majiaDJ
        // 减速马甲
        unit array majiaJS
    endglobals

    private function init takes nothing returns nothing
        local integer uid = 0
        loop
            exitwhen uid > PLAYER_NUMBER

            set ct_hbjLevel[uid] = 0
            set ct_hbjCD[uid] = 3.0
            set ct_hbjRDis[uid] = 2600.0
            set ct_hbjCount[uid] = 0
            set ct_hbjDmZf[uid] = 0.0
            set ct_hbjDongj[uid] = false
            set ct_hbjDongjLevel[uid] = 1
            set ct_hbjIsJS[uid] = false
            set ct_hbjJSLevel[uid] = 1
            set ct_hbjIsDS[uid] = false
            set ct_hbjDSCount[uid] = 3
            set ct_hbjDSDmgZf[uid] = 0.0
            set ct_hbjPzCount[uid] = 0

            set ct_hbjIsBoom[uid] = false
            set ct_hbjBoomCount[uid] = 3
            set ct_hbjBoomDmgZf[uid] = 0.0
            set ct_hbjBoomDJ[uid] = false
            set ct_hbjBoomDJLevel[uid] = 1
            set ct_hbjBoomJS[uid] = false
            set ct_hbjBoomJSLevel[uid] = 1
            set ct_hbjBoomIsDS[uid] = false
            set ct_hbjBoomPZCount[uid] = 0

            call SaveGroupHandle(hbjHash, uid, 1, CreateGroup())

            set majiaDJ[uid] = CreateUnit(Player(uid), 'N003', GetRectCenterX(getPlayerStartRect(uid)), GetRectCenterY(getPlayerStartRect(uid)), 0.0)
            set majiaJS[uid] = CreateUnit(Player(uid), 'N004', GetRectCenterX(getPlayerStartRect(uid)), GetRectCenterY(getPlayerStartRect(uid)), 0.0)
            set uid = uid + 1
        endloop
    endfunction

    // 单位(玩家1)
    private function hbjUnit1 takes nothing returns nothing 
        local integer uid = 0
        local unit u = udg_player_select_hero[uid]
        local unit bu = GetEnumUnit()
        local real damage = FF_GetAttack(u) * 0.1 * (ct_hbjDSDmgZf[uid] + 1.0)
        // 灼烧的次数
        local integer count

        if bu == null or FF_GetHp(bu) < 1.0 then
            call GroupRemoveUnit(LoadGroupHandle(hbjHash, uid, 1), bu)
        else
            set count = FF_TEMP_GetSK3(bu) + 1
            call FF_TEMP_SetSK3(bu, count)
            if count <= 5 then
                call UnitDamageTarget( u, GetEnumUnit(), damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS )
            else
                // 结束
                call FF_TEMP_SetSK3(bu, 0)
                call GroupRemoveUnit(LoadGroupHandle(hbjHash, uid, 1), bu)
            endif
        endif
        set u = null
        set bu = null
    endfunction
    // 灼烧单位(玩家2)  TODO 其他玩家的持续伤害都没写需要补充
    private function hbjUnit2 takes nothing returns nothing 
        local integer uid = 1
        local unit u = udg_player_select_hero[uid]
        local real damage = FF_GetAttack(u) * 0.1 * (ct_hbjDSDmgZf[uid] + 1.0)

        call UnitDamageTarget( u, GetEnumUnit(), damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS )
        set u = null
    endfunction
    // 灼烧单位(玩家3)
    private function hbjUnit3 takes nothing returns nothing 
        local integer uid = 2
        local unit u = udg_player_select_hero[uid]
        local real damage = FF_GetAttack(u) * 0.1 * (ct_hbjDSDmgZf[uid] + 1.0)

        call UnitDamageTarget( u, GetEnumUnit(), damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS )
        set u = null
    endfunction
    // 灼烧单位(玩家4)
    private function hbjUnit4 takes nothing returns nothing 
        local integer uid = 3
        local unit u = udg_player_select_hero[uid]
        local real damage = FF_GetAttack(u) * 0.1 * (ct_hbjDSDmgZf[uid] + 1.0)

        call UnitDamageTarget( u, GetEnumUnit(), damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS )
        set u = null
    endfunction

    // 每0.3秒执行一次
    function hbj_Every_03Second takes nothing returns nothing
        local integer uid = 0
        if ct_hbjIsDS[uid] then
            call ForGroup(LoadGroupHandle(hbjHash, 0, 1), function hbjUnit1)
        endif
        set uid = 1
        if ct_hbjIsDS[uid] then
            call ForGroup(LoadGroupHandle(hbjHash, 1, 1), function hbjUnit2)
        endif
        set uid = 2
        if ct_hbjIsDS[uid] then
            call ForGroup(LoadGroupHandle(hbjHash, 2, 1), function hbjUnit3)
        endif
        set uid = 3
        if ct_hbjIsDS[uid] then
            call ForGroup(LoadGroupHandle(hbjHash, 3, 1), function hbjUnit4)
        endif
    endfunction

    // 寒冰箭命中爆炸
    // 寒冰箭命中怪物后对100码范围造成攻击*0.5的伤害
    private function boom takes integer uid, real x, real y, unit bu returns nothing
        call relHanbjBoomAtk(uid, x, y, 500.0, 0.0, 360.0 / I2R(ct_hbjBoomCount[uid]), ct_hbjBoomCount[uid], 50.0, "tx_hanbj2.mdx", bu)
    endfunction

    // 判断单位是否被指定弹道攻击过，攻击过返回true，否则返回false
    private function isAttack takes unit u, integer id returns boolean
        local integer total = LoadInteger(skht, id, StringHash("穿透个数"))
        local integer i = 1
        loop
            exitwhen i > total
            if LoadInteger(skht, id, i) == GetHandleId(u) then
                return true
            endif
            set i = i + 1
        endloop

        set u = null
        return false
    endfunction

    // 弹道伤害  id为弹道id
    function hbj_shaped_damage takes integer uid, integer tid, integer tidi, integer id, real x, real y, real radius, real damage returns nothing

        local group g = CreateGroup()
        local boolexpr filter
        local unit ydl_unit
        local unit u = udg_player_select_hero[uid]
        local integer total = LoadInteger(skht, id, StringHash("穿透个数"))
        local integer count = LoadInteger(skht, id, StringHash("当前穿透个数"))
        
        local integer r

        set filter = Condition(function heroSkillConditions)
        call GroupEnumUnitsInRange(g, x, y, radius, filter)

        loop
            set ydl_unit = FirstOfGroup(g)
            exitwhen (ydl_unit == null)
            // 判断该单位是否已经被该弹道攻击过
            call GroupRemoveUnit(g, ydl_unit)
            if not isAttack(ydl_unit, id) and count <= total then
                // 伤害
                set count = count + 1
                call SaveInteger(skht, id, StringHash("当前穿透个数"), count)
                call SaveInteger(skht, id, count, GetHandleId(ydl_unit))

                // 范围分裂
                if ct_hbjIsBoom[uid] then
                    // 防止被其他弹道打死获取的位置是0
                    if GetUnitX(ydl_unit) == 0.0 and GetUnitY(ydl_unit) == 0.0 then
                        call boom(uid, x, y, ydl_unit)
                    else
                        call boom(uid, GetUnitX(ydl_unit), GetUnitY(ydl_unit), ydl_unit)
                    endif
                endif

                call UnitDamageTarget( u, ydl_unit, damage, true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS )

                // TODO 
                // 是否冻伤
                if ct_hbjIsDS[uid] and FF_GetHp(ydl_unit) >= 1 then
                    call GroupAddUnit(LoadGroupHandle(hbjHash, uid, 1), ydl_unit)
                endif

                // 是否冻结
                if ct_hbjDongj[uid] and FF_GetHp(ydl_unit) >= 1 then

                    call SetUnitAbilityLevel(majiaDJ[uid], 'A008', ct_hbjDongjLevel[uid])
                    call SetUnitPosition(majiaDJ[uid], GetUnitX(ydl_unit), GetUnitY(ydl_unit))
                    call IssueTargetOrder(majiaDJ[uid], "thunderbolt", ydl_unit)
                endif
                
                // 是否减速
                if ct_hbjIsJS[uid] and FF_GetHp(ydl_unit) >= 1 then
                    call SetUnitAbilityLevel(majiaJS[uid], 'A009', ct_hbjJSLevel[uid])
                    call SetUnitPosition(majiaJS[uid], GetUnitX(ydl_unit), GetUnitY(ydl_unit))
                    call IssueTargetOrder(majiaJS[uid], "slow", ydl_unit)
                endif
                
                // 如果穿透数量达到了，销毁弹道
                if count > total then
                    call DestroyEffect(LoadEffectHandle(skht, tid, tidi))
                    call RemoveSavedHandle(skht, tid, tidi)
                endif
            endif
        endloop

        call DestroyBoolExpr(filter)
        call DestroyGroup(g)

        set u = null
        set g = null
        set filter = null
        set ydl_unit = null
    endfunction

    function timer_hbj_shaped takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer tid = GetHandleId(t)
        local integer uid = LoadInteger(skht, tid, 1)
        local integer num = LoadInteger(skht, tid, 2)
        local real firstLineAngle = LoadReal(skht, tid, 3)
        local real inAngle = LoadReal(skht, tid, 5)
        local integer loopi
        local integer ecthid
        local integer count
        local integer total

        // 每次要移动的距离
        local real jl = LoadReal(skht, tid, 4) + 35
    
        // 计算出马特效的位置
        local real x
        local real y
        // 总距离
        local real totalJl = LoadReal(skht, tid, 12)

        set loopi = 0
        loop
            exitwhen loopi >= num
            
            if LoadEffectHandle(skht, tid, 20 + loopi) != null then
                set x = CosBJ(firstLineAngle) * (jl) + LoadReal(skht, tid, 6)
                set y = SinBJ(firstLineAngle) * (jl) + LoadReal(skht, tid, 7)
                // 设置弹道位置
                call EXSetEffectXY( LoadEffectHandle(skht, tid, 20 + loopi), x, y )

                // 对单位造成伤害，并且删除弹道
                set ecthid = GetHandleId(LoadEffectHandle(skht, tid, 20 + loopi))
                set total = LoadInteger(skht, ecthid, StringHash("穿透个数"))
                set count = LoadInteger(skht, ecthid, StringHash("当前穿透个数"))

                // TODO 数量，地形
                if count > total then
                    call DestroyEffect(LoadEffectHandle(skht, tid, 20 + loopi))
                    call RemoveSavedHandle(skht, tid, 20 + loopi)
                else
                    call hbj_shaped_damage(uid, tid, 20 + loopi, ecthid, x, y, 60.0, FF_GetAttack(udg_player_select_hero[uid]) * 0.5 * (1.0 + ct_hbjDmZf[uid]))
                endif
            endif

            set firstLineAngle = firstLineAngle + inAngle
            set loopi = loopi + 1
        endloop

        // 退出计时
        call SaveReal(skht, tid, 4, jl)
        if(jl >= totalJl) then

            set loopi = 0
            loop
                exitwhen loopi >= num
                set ecthid = GetHandleId(LoadEffectHandle(skht, tid, 20 + loopi))
                call DestroyEffect(LoadEffectHandle(skht, tid, 20 + loopi))
                call FlushChildHashtable(skht, ecthid)
                set loopi = loopi + 1
            endloop
            call FlushChildHashtable(skht, tid)
            call PauseTimer(t)
            call DestroyTimer(t)
        endif
    
        set t = null
    endfunction

    // 释放2 速度稍微快点，目前只有攻家BOSS在使用
    function relHanbjAtk takes integer uid, real order_x, real order_y, real distance, real angle, real inAngle, integer num, real height, string mdl returns nothing

        
        // uid - 释放玩家
        // order_x - 中心点x
        // order_y - 中心点y
        // distance - 每根线的长度距离
        // angle - 角度：箭矢射向的方向
        // inAngle - 夹角角度
        // num - 扇形数量
        // mdl - 特效模型
        // height - 特效高度
        
        // 1 根线的时候 角度是0
        // 2 根线 有 一个夹角  3 根线 有 两个夹角 也就是 num-1就是夹角数量
        // 问题在于求出第一个线的角度？
        // 1 根线的时候 角度是0                         0个夹角0
        // 2 根线的时候 角度是 angle/2                  半个夹角0.5
        // 3 根线的时候 角度是 angle                    一个夹角1
        // 4 根线的时候 角度是 angle/2 + angle          一个半夹角1.5
        // 5 根线的时候 角度是 angle*2                  两个夹角2
        // 6 根线的时候 角度是 angle/2 + angle*2        两个半夹角2.5
        // 7 根线的时候 角度是 angle + angle*2          三个夹角3

        // 第一条线的角度
        local real firstLineAngle
        local integer loopi
        local real jd
        local timer t
        local integer tid
        local effect ect
        local integer ecthid

        // 根据线的条数求出第一个线的角度
        // (num - 1) * 0.5
        set firstLineAngle = angle - I2R(num - 1) * 0.5 * inAngle

        set t = CreateTimer()
        set tid = GetHandleId(t)
        call SaveInteger(skht, tid, 1, uid)
        call SaveInteger(skht, tid, 2, num)
        call SaveReal(skht, tid, 3, firstLineAngle)
        call SaveReal(skht, tid, 5, inAngle)
        call SaveReal(skht, tid, 6, order_x)
        call SaveReal(skht, tid, 7, order_y)
        // 距离
        call SaveReal(skht, tid, 12, distance)
        
        set loopi = 0
        loop
            exitwhen loopi >= num
            
            set ect = AddSpecialEffect(mdl, order_x, order_y)
            call EXSetEffectZ( ect, getZByXY(order_x, order_y) + height )
            call EXEffectMatRotateZ(ect, firstLineAngle)

            call SaveEffectHandle(skht, tid, 20 + loopi, ect)    

            // 弹道要穿透的单位个数，最多20个  为0表示不穿透
            // 子key 1 - 穿透数量用来保存穿透的单位handid,避免重复穿透
            // 当前穿透的个数 达到 穿透个数结束弹道
            set ecthid = GetHandleId(ect)
            call SaveInteger(skht, ecthid, StringHash("穿透个数"), ct_hbjPzCount[uid])
            call SaveInteger(skht, ecthid, StringHash("当前穿透个数"), 0)


            set firstLineAngle = firstLineAngle + inAngle
            set loopi = loopi + 1
        endloop

        call TimerStart(t, 0.02, true, function timer_hbj_shaped)

        set mdl = null
        set t = null
        set ect = null
    endfunction

    function timer_relHBJAtk takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer tid = GetHandleId(t)

        local integer uid = LoadInteger(skht, tid, 1)
        local real order_x = LoadReal(skht, tid, 2)
        local real order_y = LoadReal(skht, tid, 3)
        local real dis = LoadReal(skht, tid, 4)
        local real inAngle = LoadReal(skht, tid, 6)
        local integer num = LoadInteger(skht, tid, 7)
        local real height = LoadReal(skht, tid, 8)
        local string mdl = LoadStr(skht, tid, 9)
        local integer count = LoadInteger(skht, tid, 10) + 1

        local unit bu = getNearestUnit(uid)
        local real angle = getAngleBetweenXY(GetUnitX(udg_player_select_hero[uid]), GetUnitY(udg_player_select_hero[uid]), GetUnitX(bu), GetUnitY(bu))

        call relHanbjAtk(uid, order_x, order_y, dis, angle, inAngle, num, height, mdl)

        call SaveInteger(skht, tid, 10, count)
        if count >= ct_hbjCount[uid] then
            call FlushChildHashtable(skht, tid)
            call DestroyTimer(t)
        endif

        set bu = null
        set mdl = null
        set t = null
    endfunction

    // 释放寒冰箭
    function releaseHbj takes integer uid, real order_x, real order_y returns nothing
        
        local unit bu = getNearestUnit(uid)
        local real angle = getAngleBetweenXY(GetUnitX(udg_player_select_hero[uid]), GetUnitY(udg_player_select_hero[uid]), GetUnitX(bu), GetUnitY(bu))
        // 释放数量1个，寒冰只能是1个，走分裂流
        local integer num = 1
        local real inAngle = 0.0
        local real height = 50.0
        // local string mdl = "tx_hanbj.mdx"
        local string mdl = "tx_hanbj2.mdx"
        local timer t
        local integer tid

        if getDistanceUnit(udg_player_select_hero[uid], bu) <= ct_hbjRDis[uid] then
            call relHanbjAtk(uid, order_x, order_y, ct_hbjRDis[uid], angle, inAngle, num, height, mdl)
        endif

        if ct_hbjCount[uid] > 0 then
            set t = CreateTimer()
            set tid = GetHandleId(t)
            call SaveInteger(skht, tid, 1, uid)
            call SaveReal(skht, tid, 2, order_x)
            call SaveReal(skht, tid, 3, order_y)
            call SaveReal(skht, tid, 4, ct_hbjRDis[uid])
            // call SaveReal(skht, tid, 5, angle)
            call SaveReal(skht, tid, 6, inAngle)
            call SaveInteger(skht, tid, 7, num)
            call SaveReal(skht, tid, 8, height)
            call SaveStr(skht, tid, 9, mdl)

            call TimerStart(t, 0.5, true, function timer_relHBJAtk)
        endif

        set bu = null
        set mdl = null
        set t = null
    endfunction
endlibrary



